package com.hulman.oms.util;

import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.*;

public class FileUtil
{
    /**
     * 缓冲器大小
     */
    private static final int BUFFER = 512;

    /**
     * 压缩得到的文件的后缀名
     */
    private static final String SUFFIX = ".zip";

    /**
     * 解析文件扩展名
     */
    public static String parseExtName(String fileName)
    {
        int index = fileName.lastIndexOf(".");
        if (index < 0)
        {
            return "";
        } else
        {
            return fileName.substring(index + 1);
        }
    }

    /**
     * 解析文件名
     *
     * @param fileName
     * @return
     */
    public static String parseFileName(String fileName)
    {
        int index = fileName.lastIndexOf(".");
        if (index < 0)
        {
            return fileName;
        } else
        {
            return fileName.substring(0, index);
        }
    }

    public static boolean deleteFile(File file)
    {
        //判断文件不为null或文件目录存在
        if (file == null || !file.exists())
        {
            return false;
        } else
        {
            file.delete();
            return true;
        }
    }

    /**
     * 删除文件夹下的所有文件
     *
     * @param file
     */
    public static void deleteDirectory(File file)
    {

        //取得这个目录下的所有子文件对象
        File[] files = file.listFiles();
        //遍历该目录下的文件对象
        for (File f : files)
        {
            //打印文件名
            String name = file.getName();
            //判断子目录是否存在子目录,如果是文件则删除
            if (f.isDirectory())
            {
                deleteDirectory(f);
            } else
            {
                f.delete();
            }
        }
        //删除空文件夹  for循环已经把上一层节点的目录清空。
        file.delete();
    }


    /**
     * 得到文件夹下的所有文件
     *
     * @param dirFile 压缩源文件路径
     */
    public static List<File> getAllFile(File dirFile)
    {
        List<File> fileList = new ArrayList<>();
        File[] files = dirFile.listFiles();
        for (File file : files)
        {
            //文件
            if (file.isFile())
            {
                fileList.add(file);
            } else//目录
            {
                if (file.listFiles().length != 0)
                {
                    //非空目录
                    fileList.addAll(getAllFile(file));//把递归文件加到fileList中
                } else
                {
                    //空目录
                    fileList.add(file);
                }
            }
        }
        return fileList;
    }


    /**
     * 获取相对路径
     *
     * @param dirPath 源文件路径
     * @param file    准备压缩的单个文件
     */
    private static String getRelativePath(String dirPath, File file)
    {
        File dirFile = new File(dirPath);
        String relativePath = file.getName();
        while (true)
        {
            file = file.getParentFile();
            if (file == null)
                break;
            if (file.equals(dirFile))
            {
                break;
            } else
            {
                relativePath = file.getName() + "/" + relativePath;
            }
        }
        return relativePath;
    }

    /**
     * @param destPath 解压目标路径
     * @param fileName 解压文件的相对路径
     */
    private static File createFile(String destPath, String fileName)
    {
        String[] dirs = fileName.split("/");//将文件名的各级目录分解
        File file = new File(destPath);
        if (dirs.length > 1)
        {
            //文件有上级目录
            for (int i = 0; i < dirs.length - 1; i++)
            {
                file = new File(file, dirs[i]);//依次创建文件对象知道文件的上一级目录
            }
            if (!file.exists())
            {
                file.mkdirs();//文件对应目录若不存在，则创建
            }
            file = new File(file, dirs[dirs.length - 1]);//创建文件
            return file;
        } else
        {
            if (!file.exists())
            {
                //若目标路径的目录不存在，则创建
                file.mkdirs();
            }
            file = new File(file, dirs[0]);//创建文件
            return file;
        }
    }

    /**
     * 没有指定压缩目标路径进行压缩,用默认的路径进行压缩
     *
     * @param dirPath 压缩源文件路径
     */
    public static void compress(String dirPath) throws IOException
    {
        int firstIndex = dirPath.indexOf("/");
        int lastIndex = dirPath.lastIndexOf("/");
        String zipFileName = dirPath.substring(0, firstIndex + 1) + dirPath.substring(lastIndex + 1);
        compress(dirPath, zipFileName);
    }

    /**
     * 压缩文件
     *
     * @param dirPath     压缩源文件路径
     * @param zipFileName 压缩目标文件路径
     */
    public static void compress(String dirPath, String zipFileName) throws IOException
    {
        zipFileName = zipFileName + SUFFIX;//添加文件的后缀名
        File dirFile = new File(dirPath);
        List<File> fileList = getAllFile(dirFile);
        byte[] buffer = new byte[BUFFER];
        ZipEntry zipEntry = null;
        int readLength = 0;     //每次读取出来的长度
        // 对输出文件做CRC32校验
        CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(zipFileName), new CRC32());
        ZipOutputStream zos = new ZipOutputStream(cos);
        for (File file : fileList)
        {
            if (file.isFile())
            {   //若是文件，则压缩文件
                zipEntry = new ZipEntry(getRelativePath(dirPath, file));
                zipEntry.setSize(file.length());
                zipEntry.setTime(file.lastModified());
                zos.putNextEntry(zipEntry);
                InputStream is = new BufferedInputStream(new FileInputStream(file));
                while ((readLength = is.read(buffer, 0, BUFFER)) != -1)
                {
                    zos.write(buffer, 0, readLength);
                }
                is.close();
            } else
            {
                //若是空目录，则写入zip条目中
                zipEntry = new ZipEntry(getRelativePath(dirPath, file));
                zos.putNextEntry(zipEntry);
            }
        }
        zos.close();  //最后得关闭流，不然压缩最后一个文件会出错
    }

    /**
     * @param inputStream Zip流
     * @param destPath    解压缩目标目录
     * @throws IOException
     */
    public static void decompress(InputStream inputStream, String destPath) throws IOException
    {
        ZipInputStream zis = new ZipInputStream(inputStream, Charset.forName("GBK"));
        ZipEntry zipEntry = null;
        byte[] buffer = new byte[BUFFER];//缓冲器
        int readLength = 0;//每次读出来的长度
        while ((zipEntry = zis.getNextEntry()) != null)
        {
            if (zipEntry.isDirectory())
            {
                //若是目录
                File file = new File(destPath + "/" + zipEntry.getName());
                if (!file.exists())
                {
                    file.mkdirs();
                    continue;
                }
            } else
            {
                //若是文件
                File file = createFile(destPath, zipEntry.getName());
                OutputStream os = new FileOutputStream(file);
                while ((readLength = zis.read(buffer, 0, BUFFER)) != -1)
                {
                    os.write(buffer, 0, readLength);
                }
                os.close();
            }
        }
    }

    /**
     * @param zipFileName zip文件名
     * @param destPath    解压缩目标目录
     * @throws IOException
     */
    public static void decompress(String zipFileName, String destPath) throws IOException
    {
        decompress(new FileInputStream(zipFileName), destPath);
    }
}
